package my.soft.aiteacher.common.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import my.soft.aiteacher.common.pojo.MPage;
import my.soft.aiteacher.common.pojo.UserDo;
import my.soft.aiteacher.common.pojo.VideoInformationDo;
import my.soft.aiteacher.common.pojo.VideoInformationVo;
import my.soft.aiteacher.exception.BusinessException;
import my.soft.aiteacher.student.pojo.StarRatings;
import my.soft.aiteacher.common.mapStruct.UserMapStruct;
import my.soft.aiteacher.teacher.mapStruct.CoursesMapStructs;
import my.soft.aiteacher.teacher.mapper.CoursesMapper;
import my.soft.aiteacher.teacher.mapper.FileUploadMapper;
import my.soft.aiteacher.common.mapper.UserMapper;
import my.soft.aiteacher.teacher.pojo.*;
import my.soft.aiteacher.common.mapper.VideoInformationMapper;
import my.soft.aiteacher.teacher.service.IControlService;
import my.soft.aiteacher.common.service.IVideoInformationService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 视频信息 服务实现类
 * </p>
 *
 * @author GMCX
 * @since 2025-06-06
 */
@Service
public class VideoInformationServiceImpl extends ServiceImpl<VideoInformationMapper, VideoInformationDo> implements IVideoInformationService {
    @Resource
    private VideoInformationMapper videoInformationMapper;
    @Resource
    private FileUploadMapper fileUploadMapper;
    @Resource
    private UserMapStruct userMapStruct;
    @Resource
    private UserMapper userMapper;
    @Resource
    private IControlService controlService;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private CoursesMapper coursesMapper;
    @Resource
    private CoursesMapStructs coursesMapStructs;

    @Override
    public Map<String, Object> getVideoInformationList(MPage page) {
        List<VideoInformationVo> videoInformationVoList = new ArrayList<>();
        Page<VideoInformationDo> videoInformationDoPage = videoInformationMapper.selectPage(new Page<>(page.getCurrent(), page.getSize()), new QueryWrapper<VideoInformationDo>().orderByAsc(Objects.isNull(page.getOrder()), page.getOrder()));
        videoInformationDoPage.getRecords().forEach(item -> {
            FileUpload fileUpload = fileUploadMapper.selectById(item.getFileId());
            UserDo userDo = userMapper.selectById(item.getUserId());
            userDo.setPassword(null);
            Set<Object> members = redisTemplate.opsForSet().members("StartRatings：" + item.getId());
            double average = 0;
            if (Objects.nonNull(members)) {
                List<StarRatings> starRatingsList = members.stream().map(member -> (StarRatings) member).toList();
                if (!starRatingsList.isEmpty()) {
                    average = starRatingsList.stream().mapToInt(StarRatings::getRating).average().orElse(0);
                }
            }

            CoursesVo vo = null;
            if (item.getCourseId()!=null) {
                CoursesDo coursesDo = coursesMapper.selectById(item.getCourseId());
                vo = coursesMapStructs.toVo(coursesDo);
            }

            long viewCount = getViewCount(item.getFileId());
            VideoInformationVo videoInformationVo = VideoInformationVo.builder()
                    .id(item.getId())
                    .fileInformation(fileUpload)
                    .userInformation(userMapStruct.userDoToUserVo(userDo))
                    .title(item.getTitle())
                    .description(item.getDescription())
                    .createTime(item.getCreateTime())
                    .difficulty(item.getDifficulty())
                    .tags(item.getTags())
                    .viewCount(viewCount)
                    .published(item.getPublished())
                    .starRatings(average)
                    .videoUrl(item.getVideoUrl())
                    .coursesInformation(vo)
                    .build();
            videoInformationVoList.add(videoInformationVo);
        });
        return getStringObjectMap(videoInformationVoList, videoInformationDoPage);
    }

    @Override
    public Map<String, Object> queryVideoInformationList(VideoSearch videoSearch) {
        if (Objects.isNull(videoSearch.getSearchParameter())) {
            throw new BusinessException("没有查询参数");
        }
        List<VideoInformationVo> videoInformationVoList = new ArrayList<>();
        List<Long> teacherIds = userMapper.selectList(new QueryWrapper<UserDo>().like(Objects.nonNull(videoSearch.getSearchParameter()), "name", videoSearch.getSearchParameter())).stream().map(UserDo::getId).toList();
        Page<VideoInformationDo> videoInformationDoPage = videoInformationMapper.selectPage(new Page<>(videoSearch.getCurrent(), videoSearch.getSize()), new QueryWrapper<VideoInformationDo>()
                .in(!teacherIds.isEmpty(), "user_id", teacherIds)
                .or()
                .like(!videoSearch.getSearchParameter().isEmpty(), "title", videoSearch.getSearchParameter())
                .orderByDesc(Objects.isNull(videoSearch.getOrder()), videoSearch.getOrder()));
        videoInformationDoPage.getRecords().forEach(item -> {
            CoursesVo vo = null;
            if (item.getCourseId()!=null) {
                CoursesDo coursesDo = coursesMapper.selectById(item.getCourseId());
                vo = coursesMapStructs.toVo(coursesDo);
            }
            FileUpload fileUpload = fileUploadMapper.selectById(item.getFileId());
            UserDo userDo = userMapper.selectById(item.getUserId());
            userDo.setPassword(null);
            long viewCount = getViewCount(item.getFileId());
            VideoInformationVo videoInformationVo = VideoInformationVo.builder()
                    .id(item.getId())
                    .fileInformation(fileUpload)
                    .userInformation(userMapStruct.userDoToUserVo(userDo))
                    .title(item.getTitle())
                    .description(item.getDescription())
                    .createTime(item.getCreateTime())
                    .difficulty(item.getDifficulty())
                    .tags(item.getTags())
                    .viewCount(viewCount)
                    .published(item.getPublished())
                    .coursesInformation(vo)
                    .build();
            videoInformationVoList.add(videoInformationVo);
        });
        return getStringObjectMap(videoInformationVoList, videoInformationDoPage);
    }

    @NotNull
    private Map<String, Object> getStringObjectMap(List<VideoInformationVo> videoInformationVoList, Page<VideoInformationDo> videoInformationDoPage) {
        Map<String, Object> map = new HashMap<>();
        map.put("total", videoInformationDoPage.getTotal());
        map.put("list", videoInformationVoList);
        map.put("pages", videoInformationDoPage.getPages());
        map.put("current", videoInformationDoPage.getCurrent());
        map.put("size", videoInformationDoPage.getSize());
        return map;
    }

    @Override
    public VideoInformationVo getVideoInformationDetail(Long fileId) {
        VideoInformationDo videoInformationDo = videoInformationMapper.selectOne(new QueryWrapper<VideoInformationDo>().eq("file_id", fileId));
        if (Objects.isNull(videoInformationDo)) {
            throw new BusinessException("视频不存在");
        }
        FileUpload fileUpload = fileUploadMapper.selectById(videoInformationDo.getFileId());
        UserDo userDo = userMapper.selectById(videoInformationDo.getUserId());
        userDo.setPassword(null);
        Set<Object> members = redisTemplate.opsForSet().members("StartRatings：" + videoInformationDo.getId());
        double average = 0;
        if (Objects.nonNull(members)) {
            List<StarRatings> starRatingsList = members.stream().map(member -> (StarRatings) member).toList();
            if (!starRatingsList.isEmpty()) {
                average = starRatingsList.stream().mapToInt(StarRatings::getRating).average().orElse(0);
            }
        }
        CoursesVo vo = null;
        if (videoInformationDo.getCourseId()!=null) {
            CoursesDo coursesDo = coursesMapper.selectById(videoInformationDo.getCourseId());
            vo = coursesMapStructs.toVo(coursesDo);
        }


        VideoInformationType detail = controlService.detail(fileId);

        return VideoInformationVo.builder()
                .id(videoInformationDo.getId())
                .fileInformation(fileUpload)
                .userInformation(userMapStruct.userDoToUserVo(userDo))
                .title(videoInformationDo.getTitle())
                .description(videoInformationDo.getDescription())
                .createTime(videoInformationDo.getCreateTime())
                .difficulty(videoInformationDo.getDifficulty())
                .tags(videoInformationDo.getTags())
                .published(videoInformationDo.getPublished())
                .starRatings(average)
                .videoInformationType(detail)
                .videoUrl(videoInformationDo.getVideoUrl())
                .coursesInformation(vo)
                .build();
    }

    @Override
    public List<VideoInformationVo> getHotVideoInformation() {
        Set<String> keys = redisTemplate.keys("video:view:*");
        List<VideoInformationVo> videoInformationVoList = new ArrayList<>();

        if (keys != null && !keys.isEmpty()) {
            // 按观看量排序取前3个
            List<Long> videoIds = keys.stream()
                    .map(key -> Long.parseLong(key.split(":")[2]))
                    .sorted((id1, id2) -> {
                        Long count1 = Long.parseLong(redisTemplate.opsForValue().get("video:view:" + id1).toString());
                        Long count2 = Long.parseLong(redisTemplate.opsForValue().get("video:view:" + id2).toString());
                        return count2.compareTo(count1);
                    })
                    .limit(3)
                    .collect(Collectors.toList());

            // 批量查询视频信息
            List<VideoInformationDo> videoInformationDos = videoInformationMapper.selectList(new QueryWrapper<VideoInformationDo>().in("file_id",videoIds));

            // 转换为Vo对象
            for (VideoInformationDo item : videoInformationDos) {
                FileUpload fileUpload = fileUploadMapper.selectById(item.getFileId());
                UserDo userDo = userMapper.selectById(item.getUserId());
                userDo.setPassword(null);

                VideoInformationVo videoInformationVo = VideoInformationVo.builder()
                        .id(item.getId())
                        .fileInformation(fileUpload)
                        .userInformation(userMapStruct.userDoToUserVo(userDo))
                        .title(item.getTitle())
                        .description(item.getDescription())
                        .createTime(item.getCreateTime())
                        .difficulty(item.getDifficulty())
                        .tags(item.getTags())
                        .viewCount(getViewCount(item.getFileId()))
                        .published(item.getPublished())
                        .videoUrl(item.getVideoUrl())
                        .build();

                videoInformationVoList.add(videoInformationVo);
            }
        }

        return videoInformationVoList;
    }

    @Override
    public void addVideoToCourse(VideoInformationToCourse videoInformationIds) {
        if(Objects.isNull(videoInformationIds.getCourseId())){
            throw new RuntimeException("课程不存在");
        }
        List<VideoInformationDo> videoInformationDos = videoInformationMapper.selectBatchIds(videoInformationIds.getVideoInformationIds());
        videoInformationDos.forEach(item -> {
            item.setCourseId(videoInformationIds.getCourseId());
            videoInformationMapper.updateById(item);
        });
    }


    private long getViewCount(Long videoId) {
        Object o = redisTemplate.opsForValue().get("video:view:" + videoId);
        long increment = 0L;
        if (Objects.nonNull(o)) {
            increment = Long.parseLong(o.toString());
        }
        return increment;
    }
}
